import type { BaiduPageTypeResult } from './types'
import { getAllHideSelector, getCurrentSearch } from '../../../../types/constants'
import { PageRoute } from '../../../abstract/page_route'
import { BAIDU_RESULT_BASE_SELECTOR, BaiduPageType } from './types'

export class BaiduPage extends PageRoute {
  readonly name: string = 'BaiduPage'
  private static instance: BaiduPage
  get pageType(): BaiduPageType | 'default' {
    return this.getCurrentPageMeta().type
  }

  /**
   * 获取单例实例
   */
  public static getInstance(): BaiduPage {
    if (!BaiduPage.instance) {
      BaiduPage.instance = new BaiduPage()
    }
    return BaiduPage.instance
  }

  /**
   * 获取结果选择器
   */
  getResultSelectors(pageType?: BaiduPageType, includeHideElement: boolean = false): { selector: string, container: string } {
    switch (pageType || this.pageType) {
      case BaiduPageType.Web:
        return {
          selector: `#content_left ${BAIDU_RESULT_BASE_SELECTOR}${includeHideElement ? '' : `:not(${getAllHideSelector()})`}`,
          container: '#content_left',
        }
      case BaiduPageType.News:
        return {
          selector: `#content_left ${BAIDU_RESULT_BASE_SELECTOR}${includeHideElement ? '' : `:not(${getAllHideSelector()})`}`,
          container: '#content_left',
        }
      case BaiduPageType.Video:
        return {
          selector: `#container .video_list${includeHideElement ? '' : `:not(${getAllHideSelector()})`}`,
          container: '#content_left .video_list_container',
        }
      default:
        return {
          selector: '',
          container: '',
        }
    }
  }

  /**
   * 获取当前页面类型
   */
  public getCurrentPageMeta(): BaiduPageTypeResult {
    const url = this.getCurrentUrl()
    const path = new URL(url).pathname
    const params = new URLSearchParams(new URL(url).search)
    const $element = $('#s_tab :is(#s_tab_inner, .s_tab_inner) .cur-tab')

    // 404 页面检测
    const notFoundResult = this.detectNotFoundPage()
    if (notFoundResult)
      return notFoundResult

    // 首页
    if (/^\/?$/.test(path) && params.size === 0) {
      return { type: BaiduPageType.Index }
    }

    // 基础页面检测
    const pageResult = this.detectPages(path)
    if (pageResult)
      return pageResult

    if (!$element || $element.length === 0) {
      const pd = new URLSearchParams(getCurrentSearch()).get('pd')

      switch (pd) {
        case 'note':
          return {
            type: BaiduPageType.Note,
          }
        case 'video':
          return {
            type: BaiduPageType.Video,
          }
        default:
          return {
            type: BaiduPageType.Web,
          }
      }
    }

    const content = $element.text()

    switch (content) {
      case '网页':
        return {
          type: BaiduPageType.Web,
        }
      case '资讯':
        return {
          type: BaiduPageType.News,
        }
      case '视频':
        return {
          type: BaiduPageType.Video,
        }
      case '笔记':
        return {
          type: BaiduPageType.Note,
        }
      default:
        return {
          type: 'default',
        }
    }
  }

  /**
   * 检测 404 页面
   */
  private detectNotFoundPage(): BaiduPageTypeResult | null {
    const pageNotFoundRules = [
      /404.*Not Found/i, // 不区分大小写
    ]

    if (pageNotFoundRules.some(regex => regex.test(document.title))) {
      return { type: BaiduPageType.NotFound }
    }

    return null
  }

  /**
   * 检测其他功能页面
   */
  private detectPages(basePath: string): BaiduPageTypeResult | null {
    const pageDetectors: Array<[RegExp, (...args: any[]) => BaiduPageTypeResult]> = [
      // 首页
      [/^\/index\.htm\/?$/, () => {
        return { type: BaiduPageType.Index }
      }],
      // 高级搜索
      [/^\/gaoji\/advanced\.html\/?$/, () => {
        return { type: BaiduPageType.Advanced }
      }],
      // 更多
      [/^\/more\/?$/, () => {
        return { type: BaiduPageType.More }
      }],
    ]

    for (const [regex, handler] of pageDetectors) {
      const match = basePath.match(regex)
      if (match) {
        return handler(match)
      }
    }

    return null
  }
}
